package com.xxjh.brs.uavmodeling.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.xxjh.brs.ftp.common.api.enums.ResponseStatus;
import com.xxjh.brs.ftp.common.exceptions.ConditionException;
import com.xxjh.brs.ftp.service.impl.FtpPullService;
import com.xxjh.brs.sftp.vo.FileVo;
import com.xxjh.brs.sftp.vo.FloderVo;
import com.xxjh.brs.redis.utils.RedisUtils;
import com.xxjh.brs.sftp.service.impl.PullSftpService;
import com.xxjh.brs.sftp.service.impl.PushSftpService;
import com.xxjh.brs.uavmodeling.constants.UavModelingConstant;
import com.xxjh.brs.uavmodeling.predicate.sftp.SftpSearch3dTilesPredicate;
import com.xxjh.brs.uavmodeling.service.UavModelingService;
import com.xxjh.platform.feign.client.IvasMessageFeignClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

import static com.xxjh.brs.uavmodeling.constants.UavModelingConstant.*;

/**
 * @author CHENCHEN
 * @title 无人机建模推送FTP服务
 * @company 新兴际华科技（天津）有限公司
 * @create 2024-07-03 19:21
 */
@Slf4j
@Service
public class UavModelingServiceImpl implements UavModelingService {

    @Autowired
    private FtpPullService ftpPullService;

    /*@Autowired
    private FtpPushService ftpPushService;*/

    @Autowired
    private PullSftpService pullSftpService;

    @Autowired
    private PushSftpService pushSftpService;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private IvasMessageFeignClient ivasMessageFeignClient;



    /**
     * 删除本地及FTP上对应内容。
     *
     * @param mapId 地图ID。
     * @return
     */
    @Override
    public void delFtpAndLocalDirectory(String mapId) {
        ExecutorService localExecutor = Executors.newFixedThreadPool(3);
        try {
            List<Future<Boolean>> futures = new ArrayList<>();
            //futures.add(localExecutor.submit(() -> ftpPullService.deleteFtpDirectory("")));
            /*futures.add(localExecutor.submit(() -> ftpPushService.deleteLocalDirectory(TILES_3D, mapId)));
            futures.add(localExecutor.submit(() -> ftpPushService.deleteFtpDirectory(TILES_3D, mapId)));*/
            futures.add(localExecutor.submit(() -> pushSftpService.deleteFtpDirectory(TILES_3D, mapId)));
            futures.add(localExecutor.submit(() -> pushSftpService.deleteLocalDirectory(TILES_3D, mapId)));
            for (Future<Boolean> future : futures) {
                future.get(); // 等待所有任务完成
            }
            String redisTaskIdKey = UavModelingConstant.getTaskDirectoryIdKey(mapId);
            if(redisUtils.get(ALL_TILES_KEY) != null){
                List<String> all = JSON.parseArray(redisUtils.get(ALL_TILES_KEY), String.class);
                if(redisUtils.getFromHash(redisTaskIdKey, HASH_FIELD_MESSAGE) != null){
                    List<String> msg = JSON.parseArray(redisUtils.getFromHash(redisTaskIdKey, HASH_FIELD_MESSAGE), String.class);
                    List<String> newAllList = all.stream()
                            .filter(item -> !msg.contains(item))
                            .collect(Collectors.toList());
                    redisUtils.set(ALL_TILES_KEY, JSONObject.toJSONString(newAllList));
                }
            }
            redisUtils.RemoveMemberTypeSet(TASK_IDS_SET, redisTaskIdKey);
            redisUtils.delete(redisTaskIdKey);
            redisUtils.RemoveMemberTypeSet(ALL_DIRECTORY_SET, mapId);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ConditionException(ResponseStatus.FTP_DELETE_DIRECTORY_EXCEPTION);
        } finally {
            localExecutor.shutdownNow(); // 关闭局部线程池
        }
    }

    /**
     * 查询所有地图所拥有的无人机建模3d图。
     *
     * @return 存放目录名称
     */
    @Override
    public List<FloderVo> getAllDirectory(){
        List<FloderVo> floderVoList = null;
        if(redisUtils.hasContentInSet(ALL_DIRECTORY_SET)){
            Set<String> membersFromSet = redisUtils.getMembersFromSet(ALL_DIRECTORY_SET);
            floderVoList = membersFromSet.stream()
                    .map(name -> {
                        FloderVo floderVo = new FloderVo();
                        floderVo.setFloderName(name);
                        return floderVo;
                    })
                    .collect(Collectors.toList());
        }
        return floderVoList;
    }

    /**
     * 获取建模状态。
     *
     * @param mapId 地图ID。
     * @param taskId 态势任务ID。
     */
    @Override
    public void modelingStatus(String mapId, String taskId) {
        List<FloderVo> floders = getAllDirectory();
        if(floders != null){
            boolean isContains = floders.stream().anyMatch(floder -> floder.getFloderName().equals(mapId));
            if(isContains){
                log.info("[{}] 已存在", mapId);
                throw new ConditionException(ResponseStatus.MODELING_EXIST_EXCEPTION);
            }
        }
        //任务唯一标识
        String redisTaskIdKey = UavModelingConstant.getTaskDirectoryIdKey(mapId);
        // 检查redisTaskIdKey任务是否存在
        if (redisUtils.isMemberTypeSet(TASK_IDS_SET, redisTaskIdKey)
                && STATUS_FINISHED.equals(redisUtils.getFromHash(redisTaskIdKey, HASH_FIELD_STATUS))) {
            log.info("该任务 redisTaskIdKey : [{}] 已完成", redisTaskIdKey);
            throw new ConditionException(ResponseStatus.MODELING_END_EXCEPTION);
        }
        // 检查redisTaskIdKey任务是否是RUNNING运行中状态
        if (STATUS_RUNNING.equals(redisUtils.getFromHash(redisTaskIdKey, HASH_FIELD_STATUS))) {
            log.info("该任务 redisTaskIdKey : [{}] 正在进行", redisTaskIdKey);
            throw new ConditionException(ResponseStatus.MODELING_STARTING_EXCEPTION);
        }
        log.info("redisUtils.getFromHash(taskStatusKey, STATUS): [{}]", redisUtils.getFromHash(redisTaskIdKey, HASH_FIELD_STATUS));
        //初始化查看redisTaskIdKey任务是否存在未完成任务
        if(STATUS_RELOADING.equals(redisUtils.getFromHash(redisTaskIdKey, HASH_FIELD_STATUS))){
            String message = redisUtils.getFromHash(redisTaskIdKey, HASH_FIELD_MESSAGE) != null?redisUtils.getFromHash(redisTaskIdKey, HASH_FIELD_MESSAGE).toString():null;
            log.info("获取到上次未执行完的消息内容为 redisTaskIdKey : [{}] , message : [{}]", redisTaskIdKey, message);
            //TODO：是否需要执行动作？
        }
        redisUtils.addSet(TASK_IDS_SET, redisTaskIdKey);
        redisUtils.putHash(redisTaskIdKey, HASH_FIELD_STATUS, STATUS_RUNNING);
        if(taskId != null){
            redisUtils.putHash(redisTaskIdKey, TASKID, taskId);
        }
    }

    /**
     * FTP拉取到本地，上传到FTP。
     *
     * @param mapId 地图ID。
     * @return 是否结束
     */
    @Override
    public boolean transferFtp(String mapId) {
        //任务唯一标识
        String redisTaskIdKey = getTaskDirectoryIdKey(mapId);
        log.info("执行定时任务 redisTaskIdKey : [{}]", redisTaskIdKey);
        //开始执行下载操作
        log.info("开始下载FTP内容");

        //ftp目标服务器
        ftpPullService.downloadPullFtp(TILES_3D, mapId, JSON.parseArray(redisUtils.getMembersFromSet(ALL_DIRECTORY_SET).toString(), String.class));

        //sftp目标服务器
        //pullSftpService.downloadPullFtp(TILES_3D, mapId, JSON.parseArray(redisUtils.getMembersFromSet(ALL_DIRECTORY_SET).toString(), String.class));
        log.info("开始上传本地内容");
        pushSftpService.localDirectoryUploadToFtp(TILES_3D, mapId, false);
        log.info("查找本次任务已上传内容");
        List<FileVo> fileVoList = pushSftpService.findFtpCustomizedDirectory(TILES_3D, mapId, new SftpSearch3dTilesPredicate());
        FloderVo floderVo = pushSftpService.findLastUpdateFloder(TILES_3D, mapId);
        if (Thread.currentThread().isInterrupted()) {
            log.warn("定时任务被提前结束, executeTask停止向下执行");
            return true; // 中断标记已设，提前结束循环
        }
        log.info("获取到 [{}] 目录下的最后一个修改的文件 [{}]", mapId, floderVo);
        if(floderVo != null){
            String floderName = floderVo.getFloderName();
            long updateTime = floderVo.getUpdateTime();
            if((System.currentTimeMillis()/1000 - updateTime)>900){
                log.info("最后一个文件夹 [{}] 的修改时间已经超过15分钟了，主观判定当前任务已经结束", floderName);
                redisUtils.putHash(redisTaskIdKey, HASH_FIELD_MESSAGE, JSONObject.toJSONString(fileVoList));
                redisUtils.putHash(redisTaskIdKey, HASH_FIELD_STATUS, STATUS_FINISHED);
                redisUtils.RemoveMemberTypeSet(TASK_IDS_SET, redisTaskIdKey);
                //添加当前任务的文件夹名称、路径信息到Redis中
                redisUtils.addSet(ALL_DIRECTORY_SET, mapId);
                List<FileVo> list = new ArrayList<>();
                if(redisUtils.get(ALL_TILES_KEY) != null ){
                    list = JSON.parseArray(redisUtils.get(ALL_TILES_KEY), FileVo.class);
                }
                list.addAll(fileVoList);
                redisUtils.set(ALL_TILES_KEY, JSONObject.toJSONString(list));
                log.info("所有数据以获取完毕执行关闭定时任务, redisTaskIdKey : [{}] 已完成", redisTaskIdKey);
                log.info("现有的所有数据为: {}", JSONObject.toJSONString(list));
                return true;
            }else{
                Object oldFloderName = redisUtils.getFromHash(redisTaskIdKey, FLODERNAME);
                Object oldUpdateTime = redisUtils.getFromHash(redisTaskIdKey, UPDATETIME);
                if(oldFloderName!=null && oldUpdateTime!=null
                        && floderName.equals(oldFloderName.toString())
                        && String.valueOf(updateTime).equals(oldUpdateTime.toString())){
                    log.info("说明当前获取的消息内容和上一次获取的内容一致，不做推送, redisTaskIdKey : [{}]", redisTaskIdKey);
                }else{
                    log.info("满足推送说明，调用im组件, redisTaskIdKey : [{}]", redisTaskIdKey);
                    redisUtils.putHash(redisTaskIdKey, HASH_FIELD_MESSAGE, JSONObject.toJSONString(fileVoList));
                    redisUtils.putHash(redisTaskIdKey, FLODERNAME, floderName);
                    redisUtils.putHash(redisTaskIdKey, UPDATETIME, updateTime + "");
                    String taskId = redisUtils.getFromHash(redisTaskIdKey, TASKID);
                    if(taskId != null){
                        // TODO: 调用IM告知前端拉取信息
                        //ivasMessageFeignClient.sendRefreshMessage(Long.valueOf(taskId), "load3dTilesModeling");
                        log.info("开始推送前端,告知调用接口....");
                    }
                }
            }
        }
        return false;
    }

    /**
     * 获取所有的建模信息。
     *
     * @return 所有的建模信息
     */
    @Override
    public List<FileVo> getAllTiles() {
        return JSON.parseArray(redisUtils.get(ALL_TILES_KEY), FileVo.class);
    }

    /**
     * 获取现有任务中的建模地图。
     *
     * @param mapId 地图ID。
     * @return 建模地图
     */
    @Override
    public List<FileVo> getStartingTilesByMapId(String mapId) {
        //任务唯一标识
        String redisTaskIdKey = getTaskDirectoryIdKey(mapId);
        if(redisUtils.getFromHash(redisTaskIdKey, HASH_FIELD_MESSAGE) !=null){
            log.info("getStartingTilesByMapId ====> redis中获取到");
            return JSON.parseArray(redisUtils.getFromHash(redisTaskIdKey, HASH_FIELD_MESSAGE), FileVo.class);
        }
        List<FileVo> fileVoList = pushSftpService.findFtpCustomizedDirectory(TILES_3D, mapId, new SftpSearch3dTilesPredicate());
        log.info("getStartingTilesByMapId ====> findFtpCustomizedDirectory中获取到");
        redisUtils.putHash(redisTaskIdKey, HASH_FIELD_MESSAGE, JSONObject.toJSONString(fileVoList));
        return fileVoList;
    }

    /**
     * 启动检查获取建模地图ID
     *
     * @return 地图ID集合
     */
    @Override
    public List<String> initChecking() {
        List<String> list = new ArrayList<>();
        Set<String> allDirectorys = redisUtils.getMembersFromSet(TASK_IDS_SET);
        allDirectorys.forEach(redisTaskIdKey -> {
            log.info("初始化加载init()方法，发现有未完成任务...redisTaskIdKey : [{}]", redisTaskIdKey);
            // 重新启动任务
            // 使用RedisUtils检查和设置状态
            if (redisUtils.isMemberTypeSet(TASK_IDS_SET, redisTaskIdKey)
                    && STATUS_FINISHED.equals(redisUtils.getFromHash(redisTaskIdKey, HASH_FIELD_STATUS))) {
                log.info("该任务 redisTaskIdKey : [{}] 已完成", redisTaskIdKey);
                return;
            }
            log.info("设置任务状态为初始化加载未完成任务, redisTaskIdKey : [{}] , STATUS_RELOADING", redisTaskIdKey);
            //设置任务状态为初始化加载未完成任务
            redisUtils.putHash(redisTaskIdKey, HASH_FIELD_STATUS, STATUS_RELOADING);
            String mapId = redisTaskIdKey.split("_")[1];
            log.info("mapId: [{}]", mapId);
            list.add(mapId);
        });
        return list;
    }

    /**
     * 初始化加载现有所有模型。
     *
     */
    @Override
    public void initLoading() {
        List<FileVo> list = pushSftpService.findFtpCustomizedDirectory(TILES_3D, "", new SftpSearch3dTilesPredicate());
        log.info("Get Resources 3dTiles : {}", JSONObject.toJSONString(list));
        if(list != null){
            List<FileVo> fileVos = directoryNameFilter(list);
            redisUtils.set(ALL_TILES_KEY, JSONObject.toJSONString(list));
            fileVos.forEach(ftpFileVo -> {
                redisUtils.addSet(ALL_DIRECTORY_SET, ftpFileVo.getFilePath());
                if(redisUtils.getFromHash(getTaskDirectoryIdKey(ftpFileVo.getFilePath()), HASH_FIELD_MESSAGE) == null){
                    redisUtils.putHash(getTaskDirectoryIdKey(ftpFileVo.getFilePath()), HASH_FIELD_STATUS, STATUS_FINISHED);
                    List<FileVo> fileVoList = pushSftpService.findFtpCustomizedDirectory(TILES_3D, ftpFileVo.getFilePath(), new SftpSearch3dTilesPredicate());
                    redisUtils.putHash(getTaskDirectoryIdKey(ftpFileVo.getFilePath()), HASH_FIELD_MESSAGE, JSONObject.toJSONString(fileVoList));
                }
            });
        }
    }
}
